/*
 * Copyright (C) by Fluid Operations.
 * All rights reserved.
 *
 * For more information go to http://www.fluidops.com
 */

package com.fluidops.util.help.eclipsehelp;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;

import com.fluidops.util.help.HelpContent;
import com.fluidops.util.help.IndexItem;
import com.fluidops.util.help.TOCItem;
import com.fluidops.util.help.Topic;

/**
 * @author stefan
 *
 */
public class EclipseHelpContent extends HelpContent
{
	static String nl = System.getProperty("line.separator");
	
	public boolean primary = true;
	public String pluginID = null;
	public String pluginName = null;
	public String pluginVersion = null;
	public String productName = null;
	public String productID = null;
	public String pluginVendor = null;
	
	public EclipseHelpContent()
	{}
	
	public EclipseHelpContent(HelpContent in)
	{
		super(in);
	}
	
	protected static String escape4XML(String value)
	{
		if(value == null || value.length() == 0)
			return value;

		// do the XML escape processing
//		value = value.replaceAll("\\\"", "&quot;");
		value = value.replaceAll("\\\"", "'"); // --> Eclipse Help does not show the &quot; correctly.
//		value = value.replaceAll("\\'", "&apos;"); --> does not seem to need escaping
//		value = value.replaceAll("\\<", "&lt;"); --> does not seem to need escaping
//		value = value.replaceAll("\\>", "&gt;"); --> does not seem to need escaping
		value = value.replaceAll("\\&", "&amp;");
		
		return value;
	}
	
	protected void writeTOCItems(StringBuffer doc, String prefix, TOCItem[] items)
	{
		for(TOCItem t : items)
		{
			doc.append(nl);
			doc.append(prefix);
			doc.append("<topic label=\"");
			doc.append(escape4XML(t.title));
			doc.append("\"");
			if(t.target != null)
			{
				doc.append(" href=\"");
				doc.append(escape4XML(t.target));
				doc.append("\"");
			}
			if(t.subtopics != null && t.subtopics.length > 0)
			{
				doc.append(">");
				writeTOCItems(doc, prefix + "    ", t.subtopics);
				doc.append(nl);
				doc.append(prefix);
				doc.append("</topic>");
			}
			else
				doc.append("/>");
		}
	}
	
	protected void writeIndexItems(StringBuffer doc, String prefix, IndexItem[] items)
	{
		for(IndexItem t : items)
		{
			doc.append(nl);
			doc.append(prefix);
			doc.append("<entry keyword=\"");
			doc.append(escape4XML(t.title));
			doc.append("\"");
			if((t.subtopics != null && t.subtopics.length > 0)
					|| (t.topics != null && t.topics.length > 0))
			{
				doc.append(">");
				if(t.topics != null && t.topics.length > 0)
				{
					for(Topic topic : t.topics)
					{
						doc.append(nl);
						doc.append(prefix);
						doc.append("    ");
						doc.append("<topic href=\"");
						doc.append(escape4XML(topic.target));
						if(topic.title != null)
						{
							doc.append("\" title=\"");
							doc.append(escape4XML(topic.title));
						}
						doc.append("\"/>");
					}
				}
				if(t.subtopics != null && t.subtopics.length > 0)
					writeIndexItems(doc, prefix + "    ", t.subtopics);
				doc.append(nl);
				doc.append(prefix);
				doc.append("</entry>");
			}
			else
				doc.append("/>");
		}
	}
	
	@Override
	public void write(String confFile) throws Exception
	{
		// is there already explicitly defined where to put the plugin-configuration?
		// is yes, take the path as given. if not, make sure to create a valid plugin folder structure
		if(!confFile.endsWith("plugin.xml"))
		{
			// get rid of any tailing path separators
			while(confFile.endsWith("/") || confFile.endsWith("\\"))
				confFile = confFile.substring(0, confFile.length() - 1);
			
			// do we already have the plugin subfolder?
			if(pluginID != null && pluginID.length() > 0)
			{
				// put everything in a subfolder that matches the plugin ID
				if(!confFile.endsWith(pluginID))
					confFile = confFile + "/" + pluginID;
			}
			
			// append the plugin configuration file name
			confFile = confFile + "/plugin.xml";
		}
		super.write(confFile);

		// write the TOC configuration
		StringBuffer tocDoc = new StringBuffer();
		tocDoc.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
		tocDoc.append(nl);
		tocDoc.append("<?NLS TYPE=\"org.eclipse.help.toc\"?>");
		tocDoc.append(nl);
		tocDoc.append(nl);
		
		tocDoc.append("<toc label=\"");
		tocDoc.append(escape4XML(title));
		tocDoc.append("\">");
		if(toc != null)
			writeTOCItems(tocDoc, "    ", toc);
		tocDoc.append(nl);
		tocDoc.append("</toc>");
		
		FileOutputStream tocout = new FileOutputStream(basePath + "toc.xml");
		OutputStreamWriter toc = new OutputStreamWriter(tocout, "UTF-8");
		toc.write(tocDoc.toString());
		toc.close();
		tocout.close();

		// write the index configuration
		StringBuffer indexDoc = new StringBuffer();
		indexDoc.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
		indexDoc.append(nl);
		
		indexDoc.append("<index version=\"1.0\">");
		if(index != null)
			writeIndexItems(indexDoc, "    ", index);
		indexDoc.append(nl);
		indexDoc.append("</index>");
		
		FileOutputStream indexout = new FileOutputStream(basePath + "index.xml");
		OutputStreamWriter index = new OutputStreamWriter(indexout, "UTF-8");
		index.write(indexDoc.toString());
		index.close();
		indexout.close();
		
		// write the MANIFEST.INF
		StringBuffer manifestDoc = new StringBuffer();
		manifestDoc.append("Manifest-Version: 1.0");
		manifestDoc.append(nl);
		manifestDoc.append("Bundle-ManifestVersion: 2");
		manifestDoc.append(nl);
		manifestDoc.append("Bundle-Name: Help Plug-in");
		manifestDoc.append(nl);
		manifestDoc.append("Bundle-SymbolicName: ");
		manifestDoc.append(pluginID);
		manifestDoc.append(";singleton:=true");
		manifestDoc.append(nl);
		manifestDoc.append("Bundle-Version: ");
		manifestDoc.append(pluginVersion);
		manifestDoc.append(nl);
		manifestDoc.append("Bundle-Vendor: ");
		manifestDoc.append(pluginVendor == null ? "UNKNOWN" : pluginVendor.toUpperCase());
		manifestDoc.append(nl);
		
		new File(basePath + "/META_INF").mkdirs();
		FileOutputStream manifestout = new FileOutputStream(basePath + "/META_INF/MANIFEST.MF");
		OutputStreamWriter manifest = new OutputStreamWriter(manifestout);
		manifest.write(manifestDoc.toString());
		manifest.close();
		manifestout.close();
		
		// write the plugin configuration
		StringBuffer pluginDoc = new StringBuffer();
		pluginDoc.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
		pluginDoc.append(nl);
		pluginDoc.append("<?eclipse version=\"3.0\"?>");
		pluginDoc.append(nl);
		pluginDoc.append("<plugin");
		if(pluginName != null)
		{
			pluginDoc.append(" name=\"");
			pluginDoc.append(escape4XML(pluginName));
			pluginDoc.append("\"");
		}
		if(pluginID != null)
		{
			pluginDoc.append(" id=\"");
			pluginDoc.append(escape4XML(pluginID));
			pluginDoc.append("\"");
		}
		if(pluginVersion != null)
		{
			pluginDoc.append(" version=\"");
			pluginDoc.append(escape4XML(pluginVersion));
			pluginDoc.append("\"");
		}
		if(pluginVendor != null)
		{
			pluginDoc.append(" vendor=\"");
			pluginDoc.append(escape4XML(pluginVendor));
			pluginDoc.append("\"");
		}
		pluginDoc.append(">");
		pluginDoc.append(nl);
		if(productName != null && productID != null)
		{
			pluginDoc.append("    <extension point=\"org.eclipse.core.runtime.products\"");
			if(productID != null)
			{
				pluginDoc.append(" id=\"");
				pluginDoc.append(escape4XML(productID));
				pluginDoc.append("\"");
			}
			if(productName != null)
			{
				pluginDoc.append(">");
				pluginDoc.append(nl);
				pluginDoc.append("        <product name=\"");
				pluginDoc.append(escape4XML(productName));
				pluginDoc.append("\" />");
				pluginDoc.append(nl);
				pluginDoc.append("    </extension>");
			}
			else
				pluginDoc.append(" />");
		}
		else if(productName != null || productID != null)
			throw new IllegalArgumentException("In order to define a valid help product, the product name and a product ID must be supplied!");
		pluginDoc.append(nl);
		pluginDoc.append("    <extension point=\"org.eclipse.help.toc\">");
		pluginDoc.append(nl);
		pluginDoc.append("        <toc file=\"toc.xml\"");
		if(primary)
			pluginDoc.append(" primary=\"true\" />");
		else
			pluginDoc.append(">");
		pluginDoc.append(nl);
		pluginDoc.append("    </extension>");
		pluginDoc.append(nl);
		pluginDoc.append("    <extension point=\"org.eclipse.help.index\">");
		pluginDoc.append(nl);
		pluginDoc.append("        <index file=\"index.xml\" />");
		pluginDoc.append(nl);
		pluginDoc.append("    </extension>");
		pluginDoc.append(nl);
		pluginDoc.append("</plugin>");
		
		FileOutputStream pluginout = new FileOutputStream(basePath + "plugin.xml");
		OutputStreamWriter plugin = new OutputStreamWriter(pluginout, "UTF-8");
		plugin.write(pluginDoc.toString());
		plugin.close();
		pluginout.close();
	}

}
